﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CLEXA.ClientTools.Collections
{
    public class ListBinding<TKey, TValue, T>
    {
        private readonly IReadOnlyObservableDictionary<TKey, TValue> dictionary;
        private readonly ObservableCollection<T> observableCollection;
        private readonly Func<TValue, T> converter;
        private readonly IEqualityComparer<T> identityComparer;
        private bool isBinding;

        public bool IsBinding
        {
            get { return isBinding; }
            set 
            {
                if (isBinding != value)
                {
                    if (value)
                    {
                        dictionary.ItemAdded += Dictionary_ItemAdded;
                        dictionary.ItemRemoved += Dictionary_ItemRemoved;
                        dictionary.ItemChanged += Dictionary_ItemChanged;
                        observableCollection.Clear();
                        foreach (var item in dictionary.Values)
                        {
                            observableCollection.Add(converter.Invoke(item));
                        }
                    }
                    else
                    {
                        dictionary.ItemAdded -= Dictionary_ItemAdded;
                        dictionary.ItemRemoved -= Dictionary_ItemRemoved;
                        dictionary.ItemChanged -= Dictionary_ItemChanged;
                    }
                    isBinding = value;
                }
            }
        }

        public IReadOnlyObservableDictionary<TKey, TValue> Dictionary
        {
            get { return dictionary; }
        }

        public ObservableCollection<T> ObservableCollection
        {
            get { return observableCollection; }
        }

        public ListBinding(IReadOnlyObservableDictionary<TKey, TValue> dictionary, Func<TValue, T> converter, IEqualityComparer<T> identityComparer)
        {
            this.dictionary = dictionary;
            this.observableCollection = new ObservableCollection<T>();
            this.converter = converter;
            this.identityComparer = identityComparer;
            IsBinding = true;
        }

        private void Dictionary_ItemChanged(object sender, ItemChangedEventArgs<TValue> eventArgs)
        {
            T c = converter.Invoke(eventArgs.OldValue);
            for (int i = 0; i < observableCollection.Count; i++)
            {
                if (identityComparer.Equals(observableCollection[i], c))
                {
                    observableCollection[i] = converter.Invoke(eventArgs.NewValue);
                    return;
                }
            }
        }

        private void Dictionary_ItemRemoved(object sender, ItemEventArgs<TValue> eventArgs)
        {
            T c = converter.Invoke(eventArgs.Item);
            for (int i = 0; i < observableCollection.Count; i++)
            {
                if (identityComparer.Equals(observableCollection[i], c))
                {
                    observableCollection.RemoveAt(i);
                    return;
                }
            }
        }

        private void Dictionary_ItemAdded(object sender, ItemEventArgs<TValue> eventArgs)
        {
            observableCollection.Add(converter.Invoke(eventArgs.Item));
        }
    }
}
